package org.andromda.cartridges.entity.metafacades;

import java.util.*;

import org.andromda.cartridges.entity.psm.Atributo;
import org.andromda.cartridges.entity.psm.Indice;
import org.andromda.cartridges.entity.psm.Enumeracion;
import org.andromda.cartridges.entity.psm.Tabla;
import org.andromda.cartridges.entity.psm.FuncionPHP;
import org.andromda.cartridges.entity.psm.Trigger;


import org.andromda.metafacades.uml.Entity;
import org.andromda.metafacades.uml.ModelElementFacade;
import org.andromda.metafacades.uml.PackageFacade;
import org.andromda.metafacades.uml.AssociationEndFacade;
import org.andromda.metafacades.uml.AttributeFacade;
import org.andromda.metafacades.uml.ClassifierFacade;
import org.andromda.metafacades.uml.OperationFacade;
import org.andromda.metafacades.uml.TaggedValueFacade;


/**
 * MetafacadeLogic implementation for org.andromda.cartridges.entity.metafacades.ScriptFacade.
 *
 * @see org.andromda.cartridges.entity.metafacades.ScriptFacade
 */
public class ScriptFacadeLogicImpl
    extends ScriptFacadeLogic
{

    public ScriptFacadeLogicImpl (Object metaObject, String context)
    {
        super (metaObject, context);
    }
    /**
     * @see org.andromda.cartridges.entity.metafacades.ScriptFacade#crearDB()
     */
    protected java.util.Collection handleCrearDB()
    {
    	//Collection entidades = this.getClasses();
    	Collection taggedValues = this.getTaggedValues();
    	Collection taggedValueRetornar= new ArrayList();
    	for (Iterator iterador = taggedValues.iterator(); iterador.hasNext();){
    		TaggedValueFacade taggedValue= (TaggedValueFacade) iterador.next();
    		if(!taggedValue.getName().equals("usarNombreRelaciones")){
    			taggedValueRetornar.add(taggedValue);
    			//taggedValues.remove(taggedValue);
    		}
    	}
        return taggedValueRetornar;
    }

    
    public ArrayList foundNewAttr(ClassifierFacade tabla){
    	ArrayList extraAtr = new ArrayList(); 
    	Collection relaciones = tabla.getAllGeneralizations(); 
    	Collection atributos;
    	ClassifierFacade clase;
    	String tipo_dato; 
    	
    	//manejo de las generalizaciones :)
    	for (Iterator iterador = relaciones.iterator(); iterador.hasNext();){
    		ClassifierFacade rel = (ClassifierFacade) iterador.next();
    		atributos = rel.getAttributes(); 
    		for (Iterator iterador2 = atributos.iterator(); iterador2.hasNext();){
    			AttributeFacade attr = (AttributeFacade) iterador2.next();
    			tipo_dato = attr.getType().getName();
    			extraAtr.add(GenerarAtributo(rel.getName(), attr, tipo_dato));
    		}
    	}  		
    	return extraAtr;
    }
    /**
     * @see org.andromda.cartridges.entity.metafacades.ScriptFacade#attToPostgre()
     */
    protected java.util.Collection handleAttToPostgre()
    {
    	Collection clases = this.getClasses();
    	ArrayList TablasSQL = new ArrayList();
    	ArrayList newAttr = new ArrayList();
    	Collection atributos;
    	String tipo_dato;
    	Collection TaggedValues;
    	int autoIncrement;
    	for (Iterator iterador = clases.iterator(); iterador.hasNext();){
    		ClassifierFacade clase =  (ClassifierFacade) iterador.next();
    		ArrayList atrb = new ArrayList();
    		if(clase.hasExactStereotype("Entidad")){
    			autoIncrement=-1;
    			//cargar el primary key
    			Collection valores=clase.getTaggedValues();// se obtienen todos los valores etiquetados del atributo
    			for (Iterator iterador2 = valores.iterator(); iterador2.hasNext();){
    				TaggedValueFacade taggedValue= (TaggedValueFacade) iterador.next();
    				if(taggedValue.getName().equals("autoIncrement")&& taggedValue.getValue().equals("true")){
    					if(taggedValue.getValue().equals("true")){
    						autoIncrement=1;
    					}else{
    						autoIncrement=0;
    					}
    					
    				}
    			}
    			if(autoIncrement==-1){//si no se utilizo el estereotipo por defecto es autoIncremento=true
    				autoIncrement=1;
    			}
    			if(autoIncrement==1){
    				atrb.add((new Atributo("id", "SERIAL", null, "primary key", null, null)));
    			}else{
    				atrb.add((new Atributo("id", "integer", null, "primary key", null, null)));
    			}
    			/*newAttr = foundNewAttr(clase);
    			for (Iterator iterator3 = newAttr.iterator(); iterator3.hasNext();){
					Atributo nattr = (Atributo) iterator3.next();
					atrb.add(nattr);
				}*/
    			
	    		atributos = clase.getAttributes();
	    		for (Iterator iterador2 = atributos.iterator(); iterador2.hasNext();){	    			
	    			AttributeFacade attr = (AttributeFacade) iterador2.next();
	    			tipo_dato = attr.getType().getName();
	    			//Atributo atb = GenerarAtributo(attr, tipo_dato);
	    			atrb.add(GenerarAtributo(clase.getName(), attr, tipo_dato));
	    		}
	    		Tabla tabla = new Tabla((clase.getName()+"s").toLowerCase(), null, atrb);
	    		TablasSQL.add(tabla);
    		}
    	}
        return TablasSQL;
    }
    
public ArrayList SetForeignKeys(){
	Collection clases = this.getClasses();
	String constraints = "";
	String newTables = "";
	String foreignKeys = "";
	
	ArrayList Many2ManyControl = new ArrayList();
	ArrayList returnValues = new ArrayList();
	int nrodeOrden=1;
	ArrayList auxiliar = new ArrayList();
	for (Iterator iterador = clases.iterator(); iterador.hasNext();){ //para cada clase, obtiene todas las relaciones
		ClassifierFacade clase = (ClassifierFacade) iterador.next();
		auxiliar = GetForeignKeys(clase, Many2ManyControl);
		
		for (Iterator iterador2 = auxiliar.iterator(); iterador2.hasNext();){
			
			String val = (String) iterador2.next();
			
			if (val != null)
				if (nrodeOrden==1) //primer valor del par retornado
					newTables +=val;
				else if (nrodeOrden == 3)
					constraints +=val;
				else 
					foreignKeys +=val;
			nrodeOrden+=1; 
		}
		Many2ManyControl.add(clase.getName());
	}
	returnValues.add(newTables);
	returnValues.add(foreignKeys);
	returnValues.add(constraints);
	
	
	return returnValues;
}

//Controla si la misma tabla fue creada anteriormente, sino, la crea :) 
public String CrearTablaMtoM(String tableName, String name1, String name2){
	
	String newTable;
	
	newTable = "CREATE TABLE " + tableName + "s" +
				"(\n\t"+"id SERIAL primary key, " +
				"\n\t" + name1.toLowerCase() + "_id " + " INT8 references " + name1.toLowerCase() + "s, " +
				"\n\t" + name2.toLowerCase() + "_id" + " INT8 references " + name2.toLowerCase() + "s" + 
				"\n);\n\n"
				;
	return newTable;
}


public ArrayList GetForeignKeys(ClassifierFacade table, ArrayList many2manyControl){
	Collection relaciones = table.getAssociationEnds();
	String constraints = "";
	String extraTables = "";
	ArrayList returnValues = new ArrayList();
	String tableName = "";
	String conectTo= "";
	String restricciones = "";
	String nombreConstraint = "";
	String foreignKeys = "";
	String dominante="";
	boolean sigo;
	boolean isDominante;
	boolean done; 
	for (Iterator iterador = relaciones.iterator(); iterador.hasNext();){
		done = false; 
		AssociationEndFacade rel = (AssociationEndFacade) iterador.next();
		isDominante=false;
		sigo=true;
		if (rel.isMany2Many()){
			for (Iterator iterador2 = many2manyControl.iterator(); iterador2.hasNext();){
				String valor = (String) iterador2.next();
				if (valor.equalsIgnoreCase(rel.getOtherEnd().getType().getName())){
					done = true;
					break;
				}
			}
			if (!done)
				extraTables += CrearTablaMtoM(rel.getAssociation().getName().toLowerCase(), table.getName(), rel.getOtherEnd().getType().getName());
		}else if (rel.isMany2One() || rel.isOne2One()){
			tableName = table.getName()+"s";
			conectTo = rel.getOtherEnd().getType().getName().toLowerCase();
			nombreConstraint = "FK_" + rel.getOtherEnd().getType().getName().toLowerCase() + "_" + table.getName().toLowerCase();
			if(rel.isOne2One()){
				if(rel.getAssociation().hasStereotype("Relacion")){
					//System.out.print("\n\n\n RELA"+tableName+"\n\n\n\n\n");
					Collection valores=rel.getAssociation().getTaggedValues();// se obtienen todos los valores etiquetados del atributo
					for (Iterator iterador3 = valores.iterator(); iterador3.hasNext();){
						TaggedValueFacade taggedValue= (TaggedValueFacade) iterador3.next();
						if(taggedValue.getName().equals("dominante")){
							//System.out.print("\n\n\n"+ tableName + "  " + taggedValue.getValue().toString()+ "\n\n\n\n\n");
							dominante=taggedValue.getValue().toString().toLowerCase();
							isDominante=true;
						}
					}
				}
				if(isDominante==true){
					if(dominante.equalsIgnoreCase(rel.getOtherEnd().getType().getName().toLowerCase())){//si es igual a la clase del otro extremo. Se coloca la clave foranea
						foreignKeys+= "alter table " + tableName.toLowerCase() + " ADD COLUMN " + conectTo + "_id int8 NOT NULL;\n\n";
					}else{
						sigo=false;
					}
				}else{//si no hay dominancia ambas tablas tienen el foreign key y este puede ser NULL
					foreignKeys+= "alter table " + tableName.toLowerCase() + " ADD COLUMN " + conectTo + "_id int8 NULL;\n\n";
				}
			}else{
				if(tableName.toLowerCase().equalsIgnoreCase(conectTo+"s")){
					foreignKeys+= "alter table " + tableName.toLowerCase() + " ADD COLUMN " + conectTo + "_id int8 NULL;\n\n";
				}else{
					foreignKeys+= "alter table " + tableName.toLowerCase() + " ADD COLUMN " + conectTo + "_id int8 NOT NULL;\n\n";
				}
			}
			if(sigo){
				if(rel.getOtherEnd().isComposition()){
					restricciones = "\n\ton delete cascade";
				}else{
					restricciones = "\n\ton delete restrict on update restrict";
				}
				constraints += "alter table " + tableName.toLowerCase() +
				"\n\tadd constraint " + nombreConstraint + " foreign key (" + conectTo + "_id)" +
				"\n\treferences " + conectTo + "s(id)" + restricciones + ";\n\n";
			}
		}else
			continue;
	}
	returnValues.add(extraTables);
	returnValues.add(foreignKeys);
	returnValues.add(constraints);
	return returnValues;
}
    
public Atributo GenerarAtributo(String clase, AttributeFacade attr, String tipo_dato){
	String restricsString = null;
	String CheckRestr = "";
	Collection taggedValues = attr.getTaggedValues();
	Atributo atb;
	int indicador = 0;
	
	if (tipo_dato.equalsIgnoreCase("String")){
		tipo_dato = "varchar(255)";
	}else if(tipo_dato.equalsIgnoreCase("DateTime")){
		tipo_dato="timestamp";
	}else if (tipo_dato.equalsIgnoreCase("int"))
		tipo_dato = "INT4";
	else if (tipo_dato.equalsIgnoreCase("long"))
		tipo_dato = "INT8";
	else if (tipo_dato.equalsIgnoreCase("float"))
		tipo_dato=tipo_dato.toLowerCase();
	
	//System.out.print("\n\n\n"+ clase + "  " + attr.getType().getName()+  " " + tipo_dato + "\n\n\n\n\n");
	taggedValues = attr.getTaggedValues();
	for (Iterator iterador3 = taggedValues.iterator(); iterador3.hasNext();){
		TaggedValueFacade tvf = (TaggedValueFacade) iterador3.next();
		//Calculo del tipo
		
		if (attr.getType().getName().equalsIgnoreCase("String")){ //si es del tipo String
			if(tvf.getName().equalsIgnoreCase("length")){
				if(tvf.getValue().equals("0")){//si length=0 entonces asumo que es un campo texto
					tipo_dato="TEXT";
				}else{
					tipo_dato="varchar("+tvf.getValue()+")";
				}
			}
		}
		if (tvf.getName().equalsIgnoreCase("name")){
			restricsString = "constraint ";
			if (tvf.getValue()!=null)
				restricsString += tvf.getValue() + " ";
		}
	//Calculo de la sentencia Check
		if (tvf.getName().equalsIgnoreCase("check")){
				CheckRestr = ",\n\t CHECK (" + tvf.getValue() + ")";
		}else if ((tvf.getName().equalsIgnoreCase("isUnique")) && tvf.getValue().equals("1")){
				if (restricsString == null)
					restricsString = " UNIQUE";
				else
					restricsString += " UNIQUE";
		}
		else if ((tvf.getName().equalsIgnoreCase("isNull"))){
			indicador = 1; 
			 if (tvf.getValue().equals("1")){
				 if (restricsString == null)
					 restricsString = " NULL";
				 else
					 restricsString += " NULL";
			 }else
				 if (restricsString == null)
					 restricsString = " NOT NULL";
				 else
					 restricsString += " NOT NULL";
		}
	}
	if (indicador == 0){
		if (restricsString == null){
			 restricsString = "NOT NULL";
		}else{
			 restricsString += " NOT NULL";
		}
	}
	if (!CheckRestr.isEmpty())
		atb = new Atributo(attr.getName(), tipo_dato, attr.getDefaultValue(),restricsString+CheckRestr, null, null);
	else
		atb = new Atributo(attr.getName(), tipo_dato, attr.getDefaultValue(),restricsString, null, null);
	return atb;
}


    
    /**
     * @see org.andromda.cartridges.entity.metafacades.ScriptFacade#crearEnum()
     */
    protected java.util.Collection handleCrearEnum()
    {
    	Collection enumArray = this.getClasses();
		ArrayList enumeracionArray = new ArrayList();
		String enumParams=("(");
		String enumName="";
		int cont=0;
		for (Iterator iterator = enumArray.iterator(); iterator.hasNext();) {
			ClassifierFacade clase = (ClassifierFacade) iterator.next();
			if(clase.hasExactStereotype("Enumeracion")){
				enumName = clase.getName(); //se obtiene el nombre de la enumeracion 
				Collection enumAttr = clase.getAttributes();
				for(Iterator iterator2 = enumAttr.iterator(); iterator2.hasNext();){
					if(cont>0){
						enumParams=enumParams + ",";
					}
					AttributeFacade attribute = (AttributeFacade) iterator2.next();
					enumParams=enumParams + "'" + attribute.getName()+ "'";
					cont=cont+1;
				}
				enumParams=enumParams + ")";
				Enumeracion enumera = new Enumeracion(enumName,enumParams); 
				enumeracionArray.add(enumera);
			}
		}
		
        return enumeracionArray;
    }
    private String reemplazarEspacioBlancoPorBarra(String sTexto){
    	String sCadenaSinBlancos="";
	    for (int x=0; x < sTexto.length(); x++) {
	    	  if (sTexto.charAt(x) != ' '){
	    	    sCadenaSinBlancos += sTexto.charAt(x);
	    	  }else{
	    		sCadenaSinBlancos += "_";
	    	  }
	    }
	    return sCadenaSinBlancos;
    }
    
    private int contarNombresRepetidos(ArrayList lista, String nombre, String tabla, String atributo, boolean FK){
    	int count=1;
    	int salir=0;
    	String nombreAux;
    	if(FK==true){
    		nombreAux=nombre+"_FK";
    	}else{
    		nombreAux=nombre+"_PK";
    	}
    	while(salir!=lista.size()){//tiene que ser distinto a todos los elementos
    		salir=0;
    		for (Iterator iterator = lista.iterator(); iterator.hasNext();){
    			Indice indice=(Indice) iterator.next();
	    			if(FK==false){
	    				if(indice.getNombre().equals(nombreAux)){
	    					return 0;
	    				}else{
	    					salir=salir+1;
	    				}
	    			}else{
	    				if(indice.getTabla().equals(tabla) && indice.getAtributo().equals(atributo)){
	    					return 0;
	    				}else if(indice.getNombre().equals(nombreAux)){
	    					count=count+1;
	    					salir=0;
	    					nombreAux=nombre+count+"_FK";
	    				}else{
	    					salir=salir+1;
	    				}
	    			}
	    	}
    	}
    	return count;
    }
    
    /**
     * @see org.andromda.cartridges.entity.metafacades.ScriptFacade#crearIndice()
     */
    protected java.util.Collection handleCrearIndice()
    {
    	Collection classArray = this.getClasses();
    	ArrayList indicesArray = new ArrayList();
    	String nameIndice = "";
    	String nombreTabla="";
    	String nombreAtributo="";
    	String dominante="";
    	boolean isDominante;
    	int contM2M=0;
    	int count=0;
    	boolean usarNombreRelaciones=false;
    	if(this.hasStereotype("Esquema")){
    		Collection valores=this.getTaggedValues();// se obtienen todos los valores etiquetados del esquema
			for (Iterator iterador3 = valores.iterator(); iterador3.hasNext();) {// para cada tagged value
				TaggedValueFacade taggedValue= (TaggedValueFacade) iterador3.next();
				if(taggedValue.getName().equals("usarNombreRelaciones")&& taggedValue.getValue().equals("1")){
					usarNombreRelaciones=true;
				}
			}
    	}
		for (Iterator iterator = classArray.iterator(); iterator.hasNext();) {
			ClassifierFacade clase = (ClassifierFacade) iterator.next();
			List asociacionEndList = clase.getAssociationEnds();
			nombreTabla=clase.getName().toLowerCase()+"s";
			if(clase.hasExactStereotype("Entidad")){ //si es una clase entidad se crea el indice para la clave primaria
				nameIndice=clase.getName().toLowerCase()  + "s_PK";
				nombreAtributo=clase.getName().toLowerCase();
				Indice indicePK = new Indice(nameIndice,nombreTabla,"id");
				indicesArray.add(indicePK);
			}
			//System.out.print("\n\n\n"+ nombreTabla);
			
			for (Iterator iterator2 = asociacionEndList.iterator(); iterator2.hasNext();) {//todas las asociaciones
				AssociationEndFacade asociacionEnd=(AssociationEndFacade)iterator2.next();
	    		AssociationEndFacade endB=asociacionEnd.getOtherEnd();
	 			ClassifierFacade claseB=endB.getType();
	 			nombreTabla=clase.getName().toLowerCase()+"s";
	 			isDominante=false;
	 			//System.out.print("\n\n\n"+ nombreTabla+ "  " +asociacionEnd.isMany());
				if(asociacionEnd.isOne2One() || asociacionEnd.isMany2One()){	
					if(usarNombreRelaciones==true){
						nameIndice=reemplazarEspacioBlancoPorBarra(asociacionEnd.getAssociation().getName().toLowerCase());
					}else{
						nameIndice=clase.getName().toLowerCase()  + "s_" + claseB.getName().toLowerCase() + "s";
					}
					if(asociacionEnd.isOne2One()){
						if(asociacionEnd.getAssociation().hasStereotype("Relacion")){
							Collection valores=asociacionEnd.getAssociation().getTaggedValues();// se obtienen todos los valores etiquetados del atributo
							for (Iterator iterador5 = valores.iterator(); iterador5.hasNext();){
								TaggedValueFacade taggedValue= (TaggedValueFacade) iterador5.next();
								if(taggedValue.getName().equals("dominante")){
									dominante=taggedValue.getValue().toString().toLowerCase();
									isDominante=true;
								}
							}
						}
						if(isDominante==true){
							if(dominante.equalsIgnoreCase(claseB.getName().toLowerCase())){
								isDominante=false;
							}
						}
					}
					if(isDominante==false){
						nombreAtributo=claseB.getName().toLowerCase()+"_id";
						count=contarNombresRepetidos(indicesArray,nameIndice, nombreTabla, nombreAtributo,true);
						if(count>0){//solo se agregan indices q no se aplican a las mismas tablas y columnas
							if(count>1){
								if(usarNombreRelaciones==true){
									nameIndice=reemplazarEspacioBlancoPorBarra(asociacionEnd.getAssociation().getName().toLowerCase()+count);
								}else{
									nameIndice=clase.getName().toLowerCase()  + "s_" + claseB.getName().toLowerCase() + "s"+count;
								}
							}
							//System.out.print("\n\n\n"+ nameIndice+"_FK" + "  " + nombreTabla+  " " + nombreAtributo + "\n\n\n\n\n");
							Indice indice = new Indice(nameIndice+"_FK",nombreTabla, nombreAtributo);
							indicesArray.add(indice);
						}
					}
	    		}else if(asociacionEnd.isMany2Many()){//si la asociacion es many 2 many se crea una tabla segun el nombre de la relacion
	    			//se crean los indices PK para la tabla creada
	    			nombreTabla=reemplazarEspacioBlancoPorBarra(asociacionEnd.getAssociation().getName().toLowerCase()+"s");
	    			nameIndice=nombreTabla;
					nombreAtributo=reemplazarEspacioBlancoPorBarra(asociacionEnd.getAssociation().getName().toLowerCase());
					count=contarNombresRepetidos(indicesArray,nameIndice, nombreTabla, "id",false);
					if(count!=0){
						Indice indicePK = new Indice(nameIndice+"_PK",nombreTabla,"id");
						indicesArray.add(indicePK);
					}
					//se crean los indices FK para la tabla creada
					nameIndice=asociacionEnd.getAssociation().getName().toLowerCase()+"s";
					nombreAtributo=clase.getName().toLowerCase()+"_id";
					count=contarNombresRepetidos(indicesArray,nameIndice, nombreTabla, nombreAtributo,true);
					if(count>0){
						if(count>1){
							nameIndice=reemplazarEspacioBlancoPorBarra(asociacionEnd.getAssociation().getName().toLowerCase()+"s"+count);
						}
						Indice indiceFK1 = new Indice(nameIndice+"_FK",nombreTabla, nombreAtributo);
						indicesArray.add(indiceFK1);
					}
					
					nameIndice=reemplazarEspacioBlancoPorBarra(asociacionEnd.getAssociation().getName().toLowerCase()+"s");
					nombreAtributo=claseB.getName().toLowerCase()+"_id";
					count=contarNombresRepetidos(indicesArray,nameIndice, nombreTabla, nombreAtributo,true);
					if(count>0){
						if(count>1){
							nameIndice=reemplazarEspacioBlancoPorBarra(asociacionEnd.getAssociation().getName().toLowerCase()+"s"+count);
						}
						Indice indiceFK2 = new Indice(nameIndice+"_FK",nombreTabla, nombreAtributo);
						indicesArray.add(indiceFK2);
					}
	    		}
	    	}		
		}
        return indicesArray;
    }
    /**
     * @see org.andromda.cartridges.entity.metafacades.ScriptFacade#triggertoSQL()
     */
    protected java.util.Collection handleTriggertoSQL()
    {
        Collection clases=this.getClasses();
        ArrayList triggerArray = new ArrayList();
        
        for (Iterator iterator = clases.iterator(); iterator.hasNext();) {
        	ClassifierFacade clase = (ClassifierFacade) iterator.next();
        	Collection opArr = clase.getOperations(); //se obtienen todos los atributos de la clase
        	for (Iterator iterator2 = opArr.iterator(); iterator2.hasNext();) {
        		OperationFacade operacion = (OperationFacade) iterator2.next();
        		if(operacion.hasStereotype("Trigger")){
	        		Collection valores=operacion.getTaggedValues();// se obtienen todos los valores etiquetados del atributo
	        		String evento="";
	    			String momento="";
	    			String funcion="";
	    			String retorno="NEW";
	        		for (Iterator iterador3 = valores.iterator(); iterador3.hasNext();) {// para cada tagged value
						TaggedValueFacade taggedValue= (TaggedValueFacade) iterador3.next();
		        			if(taggedValue.getName().equals("evento")){
		        				evento=(String) taggedValue.getValue();
		        			}else if(taggedValue.getName().equals("momento")){
		        				momento=(String) taggedValue.getValue();
		        				if(momento.equals("delete")){
		        					retorno="OLD";
		        				}
		        			}else if(taggedValue.getName().equals("funcion")){
		        				funcion=(String) taggedValue.getValue();
		        			}
	        		}
	        		if(funcion.length()<1){
	        			funcion="p_"+operacion.getName()+"()";
	        		}
	        		Trigger trigger = new Trigger(operacion.getName(),evento, momento, clase.getName().toLowerCase()+"s",funcion,retorno); 
	            	triggerArray.add(trigger);
        		}
        	}
        }			
        return triggerArray;
    }
}